#include "musicfile.h"
#include "music.h"
#include <QSqlError>
#include <QSqlQuery>

// 持续时长--long long  04:30.56--->(4*60+30)*1000+56毫秒 = 270*1000+56毫秒 = 270056毫秒
/**
 * @brief musicFile类的带参构造函数
 * @param url 音乐文件的URL路径
 * @details 使用给定的URL创建musicFile对象，并自动解析音乐文件的元数据。
 *          构造函数会生成唯一的音乐ID，并调用parseMediaMetaData()方法来提取音乐信息。
 * @note 此构造函数会自动调用parseMediaMetaData()方法来解析音乐文件的元数据
 */
musicFile::musicFile(const QUrl &url)
    : music_url_(url)
{
    // 读取url对应的歌曲文件信息，解析出元数据
    // 歌曲名称、歌曲作者、歌曲专辑、歌曲持续时长
    music_id_ = QUuid::createUuid().toString();
    parseMediaMetaData();
}
/**
 * @brief 设置音乐ID
 * @param music_id 音乐的唯一标识符字符串
 * @details 为音乐文件设置唯一的ID标识符，用于在数据库中唯一标识一首音乐
 */
void musicFile::setMusicId(const QString &music_id)
{
    this->music_id_ = music_id;
}
/**
 * @brief 设置音乐名称
 * @param music_name 音乐名称字符串
 */
void musicFile::setMusicName(const QString &music_name)
{
    this->music_name_ = music_name;
}
/**
 * @brief 设置音乐歌手
 * @param music_singer 音乐歌手字符串
 */
void musicFile::setMusicSinger(const QString &music_singer)
{
    this->music_singer_ = music_singer;
}
/**
 * @brief 设置音乐专辑
 * @param music_album 音乐专辑字符串
 */
void musicFile::setMusicAlbum(const QString &music_album)
{
    this->music_album_ = music_album;
}
/**
 * @brief 设置音乐时长
 * @param duration 音乐时长， qint64类型
 */
void musicFile::setMusicDuration(const qint64 duration)
{
    this->duration_ = duration;
}
/**
 * @brief 设置是否喜欢
 * @param is_like 布尔值，表示是否喜欢
 */
void musicFile::setIsLike(const bool is_like)
{
    this->is_like_ = is_like;
}
/**
 * @brief 设置是否播放历史
 * @param is_history 布尔值，表示是否在播放历史中
 */
void musicFile::setIsHistory(const bool is_history)
{
    this->is_history_ = is_history;
}
/**
 * @brief 设置音乐URL
 * @param music_url 音乐资源的URL
 */
void musicFile::setMusicUrl(const QUrl &music_url)
{
    this->music_url_ = music_url;
}
/**
 * @brief 设置歌词文件路径
 * @param lrc_file_path 歌词文件的路径字符串
 * @details 为音乐文件设置对应的歌词文件路径，用于后续加载和显示歌词
 */
void musicFile::setLrcFilePath(const QString &lrc_file_path)
{
    this->lrc_file_path_ = lrc_file_path;
}
/**
 * @brief 将音乐信息插入到数据库中
 * @details 该函数负责将音乐文件的信息保存到SQLite数据库中。
 *          首先检查数据库中是否已存在该音乐记录：
 *          - 如果存在，则更新该音乐的isLike和isHistory状态
 *          - 如果不存在，则插入新的音乐记录，包含音乐的所有元数据信息
 * @note 数据库表名为MusicInfo，包含音乐ID、名称、歌手、专辑、URL、时长、是否喜欢、是否历史播放等字段
 */
void musicFile::insertMusicToDB()
{
    // 创建SQL查询对象
    QSqlQuery query;
    // 准备查询语句，检查指定musicId的音乐是否存在
    query.prepare("SELECT EXISTS (SELECT 1 FROM MusicInfo WHERE musicId = ?)");
    query.addBindValue(music_id_); // 绑定音乐ID参数
                                   // 执行查询，如果失败则输出错误信息并返回
    if (!query.exec())
    {
        Debug << "查询失败: " << query.lastError().text();
        return;
    }
    // 如果查询结果存在
    if (query.next())
    {
        // 如果音乐已存在
        if (bool is_exists = query.value(0).toBool())
        {
            // 准备更新语句，更新音乐的喜欢状态和历史记录状态
            query.prepare("UPDATE MusicInfo SET isLike = ?, isHistory = ? WHERE musicId = ?");
            query.addBindValue(is_like_ ? 1 : 0);    // 绑定喜欢状态参数
            query.addBindValue(is_history_ ? 1 : 0); // 绑定历史记录状态参数
            query.addBindValue(music_id_);           // 绑定音乐ID参数
                                                     // 执行更新，如果失败则输出错误信息
            if (!query.exec())
                Debug << "更新失败: " << query.lastError().text();
            Debug << "更新music信息: " << music_name_ << music_id_;
        }
        else // 如果音乐不存在
        {
            // 准备插入语句，插入新的音乐信息
            query.prepare("INSERT INTO MusicInfo(musicId, musicName, musicSinger, albumName, musicUrl, duration, "
                          "isLike, isHistory) VALUES(?,?,?,?,?,?,?,?)");
            query.addBindValue(music_id_);                // 绑定音乐ID参数
            query.addBindValue(music_name_);              // 绑定音乐名称参数
            query.addBindValue(music_singer_);            // 绑定歌手名称参数
            query.addBindValue(music_album_);             // 绑定专辑名称参数
            query.addBindValue(music_url_.toLocalFile()); // 绑定音乐URL参数，转换为本地文件路径
            query.addBindValue(duration_);                // 绑定音乐时长参数
            query.addBindValue(is_like_ ? 1 : 0);         // 绑定喜欢状态参数
            query.addBindValue(is_history_ ? 1 : 0);      // 绑定历史记录状态参数

            // 执行插入，如果失败则输出错误信息并返回
            if (!query.exec())
            {
                Debug << "插入失败: " << query.lastError().text();
                return;
            }
            Debug << "插入music信息: " << music_name_ << music_id_;
        }
    }
}
/**
 * @brief 获取音乐ID
 * @return 返回音乐ID字符串
 */
QString musicFile::getMusicId() const
{
    return music_id_;
}

/**
 * @brief 获取音乐名称
 * @return 返回音乐名称字符串
 */
QString musicFile::getMusicName() const
{
    return music_name_;
}
/**
 * @brief 获取音乐歌手
 * @return 返回音乐歌手字符串
 */
QString musicFile::getMusicSinger() const
{
    return music_singer_;
}
/**
 * @brief 获取音乐专辑
 * @return 返回音乐专辑字符串
 */
QString musicFile::getMusicAlbum() const
{
    return music_album_;
}
/**
 * @brief 获取音乐时长
 * @return 返回音乐时长， qint64类型
 */
qint64 musicFile::getMusicDuration() const
{
    return duration_;
}
/**
 * @brief 获取是否喜欢状态
 * @return 返回布尔值，表示是否喜欢
 */
bool musicFile::getIsLike() const
{
    return is_like_;
}
/**
 * @brief 获取是否在播放历史中
 * @return 返回布尔值，表示是否在播放历史中
 */
bool musicFile::getIsHistory() const
{
    return is_history_;
}
/**
 * @brief 获取音乐URL
 * @return 返回音乐资源的URL
 */
QUrl musicFile::getMusicUrl() const
{
    return music_url_;
}
/**
 * @brief 获取歌词文件路径
 * @return 返回歌词文件路径字符串
 * @details 根据音乐文件的URL自动生成对应的歌词文件路径，
 *          通过将音乐文件扩展名替换为.lrc来得到歌词文件路径
 */
QString musicFile::getLrcFilePath() const
{
    QString lrc_path = music_url_.toLocalFile();
    lrc_path.replace(".mp3", ".lrc");
    lrc_path.replace(".flac", ".lrc");
    lrc_path.replace(".mpga", ".lrc");

    return lrc_path;
}
/**
 * @brief 解析媒体文件的元数据信息
 *
 * 通过QMediaPlayer读取音乐文件的元数据，包括歌曲名、歌手、专辑和时长等信息。
 * 如果元数据中没有相关信息，则从文件名中提取信息作为补充。
 *
 * @note 此函数没有参数
 * @note 此函数没有返回值
 */
void musicFile::parseMediaMetaData()
{
    // 解析时候需要读取歌曲数据，读取歌曲⽂件需要⽤到QMediaPlayer类
    QMediaPlayer player;
    player.setSource(music_url_);
    player.play();
    // 媒体元数据解析需要时间，只有等待解析完成之后，才能提取⾳乐信息，此处循环等待
    // 循环等待时：主界⾯消息循环就⽆法处理了，因此需要在等待解析期间，让消息循环继续处理
    while (player.metaData().isEmpty())
        QCoreApplication::processEvents();

    if (!player.metaData().isEmpty()) // 检查媒体元数据是否为空
    {
        // 从媒体元数据中获取音乐信息
        music_name_ = player.metaData().value(QMediaMetaData::Title).toString();                // 获取歌曲名称
        music_singer_ = player.metaData().value(QMediaMetaData::ContributingArtist).toString(); // 获取歌手信息
        music_album_ = player.metaData().value(QMediaMetaData::AlbumTitle).toString(); // 从媒体元数据中获取专辑标题信息
        duration_ = player.duration();                                                 // 获取媒体播放总时长

        // 从文件名中提取歌曲名和歌手信息
        const QString file_name = music_url_.fileName();
        const qint64 index = file_name.indexOf('-');
        // 检查音乐名称是否为空，如果为空则进行处理
        if (music_name_.isEmpty())
        {
            // 如果index不为-1，表示文件名中包含分隔符（如"-"）
            if (index != -1)
                // 从文件名开头截取到分隔符位置，并去除首尾空格
                music_name_ = file_name.mid(0, index).trimmed();
            else
                // 如果没有分隔符，则从文件名开头截取到第一个点号（扩展名）之前，并去除首尾空格
                music_name_ = file_name.mid(0, file_name.indexOf('.')).trimmed();
        }
        // 检查歌手名称是否为空，如果为空则进行处理
        if (music_singer_.isEmpty())
        {
            // 如果index不为-1，表示文件名中包含分隔符
            if (index != -1)
                // 从分隔符后截取到扩展名之前，作为歌手名称，并去除首尾空格
                music_singer_ = file_name.mid(index + 1, file_name.indexOf('.') - index - 1).trimmed();
            else
                // 如果没有分隔符，则设置歌手为"未知歌手"
                music_singer_ = "未知歌手";
        }
        // 检查专辑名称是否为空，如果为空则进行处理
        if (music_album_.isEmpty())
        {
            // 如果index不为-1，表示文件名中包含分隔符
            if (index != -1)
                // 设置专辑为"未知专辑"
                music_album_ = "未知专辑";
        }
        // 调试输出：打印原始文件名
        Debug << file_name;
        // 调试输出：打印解析后的音乐名称、歌手、专辑和时长信息
        Debug << music_name_ << music_singer_ << music_album_ << duration_;
    }
}
